#ifndef NET_SOCKET_H
#define NET_SOCKET_H

#include <string>
#include <cstdint>
#include <cstring>
#include <csignal>
#include <cerrno>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include "logger.h"

namespace net {

/**
 * @brief 在程序初始化时忽略 SIGPIPE 信号
 * 以避免因向已关闭的套接字写入数据而导致程序崩溃
 */
class NetWork 
{
public:
    NetWork() 
    {
        LOG_INFO("SIGPIPE INIT");
        signal(SIGPIPE, SIG_IGN);  // 忽略 SIGPIPE 信号
    }
};

static NetWork nw;
/**
 * @brief 套接字类封装，提供TCP套接字的基本操作
 * 支持创建服务器/客户端套接字、绑定、监听、连接、收发数据等功能
 */
class Socket 
{
private:
    int _sockfd;  // 套接字文件描述符，-1表示无效

public:
    /**
     * @brief 默认构造函数
     * 创建一个未初始化的Socket对象
     */
    Socket() : _sockfd(-1) {}

    /**
     * @brief 使用现有文件描述符构造Socket对象
     * @param fd 已有的套接字文件描述符
     */
    explicit Socket(int fd) : _sockfd(fd) {}

    /**
     * @brief 析构函数
     * 自动关闭套接字(如果未关闭)
     */
    ~Socket() { close(); }

    /**
     * @brief 获取套接字文件描述符
     * @return 套接字文件描述符
     */
    int fd() const { return _sockfd; }

    /**
     * @brief 创建TCP套接字
     * @return 成功返回true，失败返回false
     */
    bool create();

    /**
     * @brief 绑定IP地址和端口
     * @param ip 要绑定的IP地址
     * @param port 要绑定的端口号
     * @return 成功返回true，失败返回false
     */
    bool bind(const std::string &ip, uint16_t port);

    /**
     * @brief 开始监听连接
     * @param backlog 最大等待连接队列长度，默认使用系统推荐值SOMAXCONN
     * @return 成功返回true，失败返回false
     */
    bool listen(int backlog = SOMAXCONN);

    /**
     * @brief 连接到远程服务器
     * @param ip 服务器IP地址
     * @param port 服务器端口号
     * @return 成功返回true，失败返回false
     */
    bool connect(const std::string &ip, uint16_t port);

    /**
     * @brief 接受新连接(仅服务器模式)
     * @return 新连接的套接字文件描述符，失败返回-1
     */
    int accept();

    /**
     * @brief 接收数据(阻塞模式)
     * @param buf 接收缓冲区
     * @param len 缓冲区长度
     * @param flags 接收标志，默认0表示阻塞接收
     * @return 成功返回接收的字节数，失败返回-1，非阻塞模式下无数据返回0
     */
    ssize_t recv(void *buf, size_t len, int flags = 0);

    /**
     * @brief 非阻塞接收数据
     * @param buf 接收缓冲区
     * @param len 缓冲区长度
     * @return 成功返回接收的字节数，失败返回-1，无数据返回0
     */
    ssize_t nonBlockRecv(void *buf, size_t len);

    /**
     * @brief 发送数据(阻塞模式)
     * @param buf 发送缓冲区
     * @param len 要发送的数据长度
     * @param flags 发送标志，默认0表示阻塞发送
     * @return 成功返回发送的字节数，失败返回-1
     */
    ssize_t send(const void *buf, size_t len, int flags = 0);

    /**
     * @brief 非阻塞发送数据
     * @param buf 发送缓冲区
     * @param len 要发送的数据长度
     * @return 成功返回发送的字节数，失败返回-1
     */
    ssize_t nonBlockSend(void *buf, size_t len);

    /**
     * @brief 关闭套接字
     * 安全关闭套接字并重置文件描述符
     */
    void close();

    /**
     * @brief 创建服务器套接字(一站式初始化)
     * 依次调用Create、SetNonBlock、Bind、Listen、ReuseAddress
     * @param port 监听端口
     * @param ip 监听IP地址，默认0.0.0.0表示所有接口
     * @param nonBlock 是否设置为非阻塞模式，默认false
     * @return 成功返回true，失败返回false
     */
    bool createServer(uint16_t port, const std::string &ip = "0.0.0.0", bool nonBlock = false);

    /**
     * @brief 创建客户端套接字(一站式初始化)
     * 依次调用Create、Connect
     * @param port 服务器端口
     * @param ip 服务器IP地址
     * @return 成功返回true，失败返回false
     */
    bool createClient(uint16_t port, const std::string &ip);

    /**
     * @brief 设置地址和端口重用
     * 允许在同一IP和端口上重启服务器，避免TIME_WAIT状态影响
     */
    void reuseAddress();

    /**
     * @brief 设置长连接
     * 在已连接的套接字上定期传输消息，检测网络中失效的对等方
     */
    void setKeepAlive();

    /**
     * @brief 禁用Nagle算法
     * 允许小数据包立即发送
     */
    void setTcpNoDelay();

    /**
     * @brief 设置套接字阻塞模式
     * @param nonBlock true表示设置为非阻塞模式，false表示设置为阻塞模式
     */
    void setNonBlock(bool nonBlock = true);
};

} // namespace net

#endif // NET_SOCKET_H